#!/bin/bash
#
# functions - networking-vpp driver devstack utility functions

function install_vpp {
  if is_fedora; then
      # TODO(ijw) should be more constructed from what we're running on
      repourl=${vpp_repourl:-https://packagecloud.io/fdio/$VPP_BRANCH/el/7/'$basearch'}
      sudo tee /etc/yum.repos.d/fdio.repo <<EOF
[fdio-master]
name=fd.io master branch latest merge
baseurl=$repourl
enabled=1
gpgcheck=0
EOF
  sudo yum --enablerepo=fdio-master clean metadata
  elif is_ubuntu; then
      repourl=${vpp_repourl:-https://packagecloud.io/fdio/$VPP_BRANCH/ubuntu/}
      sudo tee  /etc/apt/sources.list.d/99fd.io.list <<EOF
deb [trusted=yes] $repourl `lsb_release -cs` main
EOF
      # installing to prevent failure with https hosts on fd.io source
      install_package apt-transport-https
  else
      die $LINENO "Can't install VPP on unsupported os: $os_VENDOR"
  fi
  # stack fails without this package, ensuring it's installed
  install_package bridge-utils
  install_package vpp
  # if vpp service is started while installing it will not have correct
  # startup conf yet, stop the service it will be started later
  stop_service vpp || true

  # install the python3 papi package (Centos and Ubuntu pkg names differ)
  install_package python3-vpp-api || install_package vpp-api-python3

  # From 19.04, we need an additional pip package for vpp-api-python,
  # and it doesn't properly depend upon it
  pip_install aenum

  # plugins are required to support security groups
  # (names changed post-19.01)
  install_package vpp-plugins || install_package vpp-plugin-core vpp-plugin-dpdk
  if is_set VPP_STARTUP_CONFIG; then
      if [[ -f "$VPP_STARTUP_CONFIG" && -r "$VPP_STARTUP_CONFIG" ]]; then
          sudo cp -f /etc/vpp/startup.conf /etc/vpp/startup.conf.devstack_bak || true
          sudo cp -f $VPP_STARTUP_CONFIG /etc/vpp/startup.conf
      else
          die $LINENO "VPP config file $VPP_STARTUP_CONFIG not a file or unreadable"
      fi
      echo "NOTE: startup config file should specify all add-ons required by networking-vpp"
      echo "NOTE: devstack plugin no longer adds uid settings, startup file, etc."
  else
      # keep a copy of un-modified initial config file
      sudo cp -f /etc/vpp/startup.conf /etc/vpp/startup.conf.devstack_bak || true
      # We start from our base config file ('startup.yaml')
      # We add some settings
      # VPP 17.10 will not open a socket for vppctl unless you ask
      # TODO: note that the 'tap' interface for uplink is *not* automatically created
      user="$(id -un)"
      group="$(id -gn)"
      sudo touch /etc/vpp-startup.conf
(      cat <<EOF
unix:
EOF
    if [ "$VPP_INT_PCI_DEV" != "" ] ; then
      echo "    dev: \"$VPP_INT_PCI_DEV\""
    fi
    cat <<EOF
    cli-listen: /run/vpp/cli.sock
    gid: $group
    startup-config: /etc/vpp-startup.conf

api-segment:
    uid: $user

EOF
) >/tmp/addons
      thisdir="$DEST/networking-vpp/devstack/"
      addl_startup=/tmp/addons

      if [ "$VPP_BRANCH" -le 1901 ] ; then
          addl_startup="$addl_startup "$thisdir"/1901pre.yaml"
      fi

      if [ -z "$VPP_STARTUP_OVERRIDE_CONFIG" ] ; then
          python "$thisdir"/make-config.py "$thisdir"/startup.yaml $addl_startup
      else
          python "$thisdir"/make-config.py "$thisdir"/startup.yaml $addl_startup "$VPP_STARTUP_OVERRIDE_CONFIG"
      fi | sudo tee /etc/vpp/startup.conf >/dev/null

  fi

}

function start_vpp {
    install_vpp
    # Start if not started; restart if stopped, because we have changed config
    restart_service vpp
}

function set_hugepages {
    if is_set NR_HUGEPAGES; then
        system_hugepages="$(cat /proc/meminfo | grep HugePages_Total | awk '{print $2}')"
        die_if_not_set $LINENO system_hugepages "Couldn't determine current system huge page count"
        if [ "$system_hugepages" -lt  "$NR_HUGEPAGES" ]; then
            sudo sysctl -w vm.nr_hugepages="$NR_HUGEPAGES"
            system_hugepages=$(cat /proc/meminfo | grep HugePages_Total | awk '{print $2}')
            if [ "$system_hugepages" -ne  "$NR_HUGEPAGES" ]; then
                die $LINENO "Failed to set system huge page count to $NR_HUGEPAGES"
            fi
        fi
        # TODO(ijw): max_map_count wants to be *way* bigger than twice this, some other elements of
        # openstack share memory with each other
    fi
}

function setup_host_env {
    if is_service_enabled etcd3; then
        # We don't need to run it for ourselves, it's a devstack service
        RUN_ETCD=no
        if [ "$CLEAN_ETCD" = "yes" ] ; then
            # Need to trap the etcd3 startup
            eval "$(echo -n _vpp_orig_; declare -f start_etcd3)"
            start_etcd3() {
                _vpp_orig_start_etcd3
                clean_etcd_vpp_area
            }
        fi
    fi

    if [ "$RUN_ETCD" = "yes" ] ; then
        # TODO(ijw): in fact, we may not need to run it at all (it might be
        # remote) - should add an option...
        is_package_installed etcd || install_package etcd
        restart_service etcd
        if [ "$CLEAN_ETCD" = "yes" ] ; then
            clean_etcd_vpp_area
        fi
    fi

    set_hugepages
    start_vpp
}


function clean_etcd_vpp_area() {
    # This relies on a bunch of etcd state, and if you're stacking and unstacking
    # stale cruft builds up.
    # This is not a good idea if you're running multiple controllers, but it's
    # fine for a single controller system.

    # etcd_host may be complex, so we do our best with it
    if [ ! -z "$ETCD_CA_CERT" ] ; then
         proto=https
         args="--ca-file $ETCD_CA_CERT"
    else
         proto=http
         args=""
    fi

    if [[ ! "$ETCD_HOST" =~ "://" ]] ; then
        hostarg=""
        for f in $(echo "$ETCD_HOST" | tr "," "\n"); do
            hostarg="$hostarg,$proto://$f:$ETCD_PORT/"
        done
        # Strip that leading comma

        hostarg="${hostarg:1}"
    else
        hostarg="$ETCD_HOST"
    fi
    args="$args --endpoints $hostarg"

    # TODO(ijw): deal with username and password

    sleep 2 # settle time for the daemon
    etcdctl $args rm --recursive /networking-vpp 2>/dev/null ||:
}
